﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LibUsbDotNet;
using LibUsbDotNet.Main;
using LibUsbDotNet.WinUsb;

namespace Lipesin.MP710
{
	/// <summary>
	/// Драйвер контроллера MP710
	/// </summary>
	public class MP710Driver
	{
		#region enum
		private enum RequestType : byte
		{
			//libusb_request_recipient
			/** Device */
			LIBUSB_RECIPIENT_DEVICE = 0x00,

			/** Interface */
			LIBUSB_RECIPIENT_INTERFACE = 0x01,

			/** Endpoint */
			LIBUSB_RECIPIENT_ENDPOINT = 0x02,

			/** Other */
			LIBUSB_RECIPIENT_OTHER = 0x03,


			//libusb_request_type
			/** Standard */
			LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5),

			/** Class */
			LIBUSB_REQUEST_TYPE_CLASS = (0x01 << 5),

			/** Vendor */
			LIBUSB_REQUEST_TYPE_VENDOR = (0x02 << 5),

			/** Reserved */
			LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5),

			//libusb_endpoint_direction
			/** In: device-to-host */
			LIBUSB_ENDPOINT_IN = 0x80,

			/** Out: host-to-device */
			LIBUSB_ENDPOINT_OUT = 0x00
		}
		#endregion enum
		IUsbInterface _iusb;

		public MP710Driver()
		{
			
			UsbRegDeviceList list = WinUsbDevice.AllLibUsbDevices;
			UsbRegistry r = list.Find((registry) => registry.Vid == 0x16c0 && registry.Pid == 0x05df);
			if (r == null) throw new Exception("Устройство не найдено.");
			UsbDevice device = r.Device;
			_iusb = device as IUsbInterface;
			_iusb.Open();
			bool opened = _iusb.IsOpen;
			if (!opened)throw new Exception("Устройство не открылось.");
			Reset();
		}
		/// <summary>
		/// Устанавливает значение порта
		/// </summary>
		/// <param name="portNumber">Номер порта</param>
		/// <param name="signal">Наличие сигнала</param>
		public void SetPort(byte portNumber, bool signal)
		{
			bool opened = _iusb.IsOpen;
			if (!opened) throw new Exception("Устройство не открыто.");
			byte[] buf = new byte[8];
			buf[0] = 0x63;
			buf[1] = portNumber;
			buf[2] = signal ? (byte)128 : (byte)0;
			buf[3] = 0;
			buf[5] = 15;
			buf[7] = 15;
			int outLen;
			UsbSetupPacket packet = new UsbSetupPacket
				(
					Convert.ToByte(RequestType.LIBUSB_REQUEST_TYPE_CLASS | RequestType.LIBUSB_RECIPIENT_INTERFACE | RequestType.LIBUSB_ENDPOINT_OUT),
					0x9,
					0x300,
					0,
					8
				);
			bool success;
			int errorCount = 0;
			do
			{
				success = _iusb.ControlTransfer(ref packet, buf, 8, out outLen);
				if (!success)
				{
					errorCount++;
					_iusb.Close();
					_iusb.Open();
				}
			} while (!success && errorCount < 3);
			if (!success) throw new Exception("Запрос не прошёл.");
		}
		/// <summary>
		/// Сбрасывает питание со всех портов
		/// </summary>
		public void Reset()
		{
			for (byte i = 0; i < 16; i++)
				SetPort(i, false);
		}
	}
}
